package org.langqiao.jvm.base;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class CompileClassLoader extends ClassLoader{

	@SuppressWarnings("unused")
	//读取一个文件的内容
	private byte[] getBytes(String filename) throws IOException{
		File file = new File(filename);
		long len = file.length();
		byte[] raw = new byte[(int) len];
		FileInputStream fin = new FileInputStream(file);
		int r = fin.read(raw);
		if(r != len){
			throw new IOException("无法读取全部文件：" + r + "!=" + len);
		}
		fin.close();
		return raw;
	}
	
	private boolean compile(String javaFile) throws IOException{
		System.out.println("ComplieClassLoader:正在编译"+javaFile +"......");
		Process p = Runtime.getRuntime().exec("javac " + javaFile);
		try {
			p.waitFor();
		} catch (InterruptedException e) {
			e.printStackTrace();
			System.out.println(e);
		}
		//获取javac线程的退出值
		int ret = p.exitValue();
		return ret==0;
	}
	
	//重写ClassLoader类的findClass方法
	protected Class<?> findClass(String name){
		Class clazz = null;
		String fileStub = name.replaceAll(".", "/");
		String javaFileName = fileStub + ".java";
		String classFileName = fileStub + ".class";
		File javaFile = new File(javaFileName);
		File classFile = new File(classFileName);
		
		//如果java文件存在并且class文件不存在，或者是java文件的最后修改时间比class文件的最后修改时间要晚时，重新编译
		if(javaFile.exists() && (!classFile.exists()) || javaFile.lastModified() > classFile.lastModified()){
			try {
				if(!compile(name) || !classFile.exists()){
					throw new ClassNotFoundException("ClassNotFoundException:" + javaFileName);
				}
			} catch (IOException e) {
				e.printStackTrace();
			} catch (ClassNotFoundException e) {
				e.printStackTrace();
			}
		}
		
		if(classFile.exists()){
			//将class的二进制数据读入数组
			
			try {
				byte[] raw = getBytes(classFileName);
				//调用ClassLoader的defineClass方法将二进制数据转化为class对象
				clazz = defineClass(name, raw, 0,raw.length);
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		return clazz;
	}
	public static void main(String[] args) throws ClassNotFoundException, SecurityException, NoSuchMethodException, IllegalArgumentException, IllegalAccessException, InvocationTargetException {
		//如果运行该程序时没有参数，既没有目标类
		if(args.length<1){
			System.out.println("缺少运行的目标类，请按如下格式运行Java源文件");
			System.out.println("java CompileClassLoader className");
			String progClass = args[0];
			String[] progArgs = new String[args.length-1];
			System.arraycopy(args, 1, progArgs, 0, progArgs.length);
			CompileClassLoader ccl = new CompileClassLoader();
			Class<?> clazz = ccl.loadClass(progClass);
			Method main = clazz.getMethod("main", (new String[0]).getClass());
			Object[] argsArray = {progArgs};
			main.invoke(null, argsArray);
		}
	}

}
